#!/usr/bin/env python

import os
import pdb
import pwd
import re
import shutil
import socket
import subprocess
import sys
import time
import traceback as tb
import urllib2
from daemon import Daemon
from SocketServer import *

# ---------------------------------------------------------------------------
class ezpub_server(TCPServer):
    def __init__(self, *args):
        TCPServer.__init__(self, *args)
        self.allow_reuse_address = True
        
# ---------------------------------------------------------------------------
class ezpub_handler(StreamRequestHandler):
    # -----------------------------------------------------------------------
    def handle(self):
        # now = time.strftime("%Y.%m%d %H:%M:%S")
        self.data = self.rfile.readline().strip()
        log("=== New request %s -> '%s'" % (self.client_address[0], self.data))

        if self.data.startswith("T "):
            self.thredds_request(self.data)
        elif self.data.startswith("C "):
            self.copy_request(self.data)
        elif self.data == "I":
            self.ingest_request(self.data)
        elif self.data == "R":
            self.reinit_thredds_request(self.data)
        elif self.data.startswith("X "):
            self.xref_request(self.data)
        else:
            self.throw("FAIL: unrecognized request '%s'" % self.data)
            
    # -----------------------------------------------------------------------
    def copy_request(self, data):
        try:
            (c, src, dest) = re.split("\s+", data)
            if c != "C":
                self.throw("FAIL: bad request '%s'" % c)
                return
            
            if not os.path.exists(src):
                self.throw("FAIL: source file '%s' not found" % src)
                return
            
            ddir = os.path.dirname(dest)
            if not os.path.exists(ddir):
                try:
                    os.makedirs(ddir)
                except Exception, e:
                    self.throw("FAIL: os.makedirs fails (%s)" % str(e))
                    return
                
            try:
                shutil.copy(src, dest)
            except Exception, e:
                self.throw("FAIL: shutil.copy(%s, %s) fails (%s)"
                           % (src, dest, str(e)))
                return
            
            self.throw("OK")

        except Exception, e:
            self.throw("FAIL: copy_request fails (%s)" % str(e))

    # -----------------------------------------------------------------------
    def ingest_request(self, data):
        try:
            if data != "I":
                self.throw("FAIL: bad request '%s'" % data)
                return

            # call the harvester to ingest the current THREDDS catalog
            # into the Solr index
            log("calling harvester...")
            webinf = "/usr/local/tomcat/webapps/esg-search/WEB-INF"
            os.environ['CLASSPATH'] = "%s/classes" % webinf
            log("CLASSPATH = '%s'" % os.getenv('CLASSPATH'))
            cmd = ["/usr/local/java/bin/java",
                   "-Djava.ext.dirs=%s/lib" % webinf,
                   "-Dlog4j.configuration=%s/classes/log4j.xml" % webinf,
                   "esg.search.publish.impl.PublishingServiceMain",
                   "http://%s/thredds/esgcet/catalog.xml" % socket.gethostname(),
                   "THREDDS",
                   "true"]
            log("running '%s'" % " ".join(cmd))
            proc = subprocess.Popen(cmd,
                                    stdout=subprocess.PIPE,
                                    stderr=subprocess.STDOUT)
            result = "".join(proc.stdout.readlines())
            for line in result.split("\n"):
                log(line)
            log("back from calling harvester")

            if "Exception" in result:
                self.throw("FAIL: Java threw exception")
                return
            
            self.throw("OK")
            
        except Exception, e:
            self.throw("FAIL: ingest_request fails (%s)" % str(e))
            
    # -----------------------------------------------------------------------
    def reinit_thredds_request(self, data):
        try:
            if data != "R":
                self.throw("FAIL: bad request '%s'" % data)
                return
            
            log("Reinitializing THREDDS server")

            reinit_url = "https://localhost:443/thredds/admin/debug?catalogs/reinit"
            reinit_ok = "reinit ok"
            reinit_err_url = "https://localhost:443/thredds/admin" \
                             + "/content/logs/catalogInit.log"
            reinit_err = "Catalog init"
            reinit_fatal = "**Fatal"
            tuser = "dnode_user"
            if "esg-vm-demo01" in socket.gethostname():
                tpass = "esgrocks"
            elif "esg-vm-demo02" in socket.gethostname():
                tpass = "esg4ever"
            else:
                self.throw("FAIL: db password not known for host %s"
                           % socket.gethostname())
                return
            
            result = ""
            try:
                result = auth_read_thredds(reinit_url, tuser, tpass)
            except Exception, e:
                msg = `e`
                if msg.find("maximum recursion depth") != -1:
                    self.throw("FAIL: bad password (%s)" % msg)
                else:
                    self.throw("FAIL: %s" % tb.format_exc())
                return

            if result.find(reinit_ok) == -1:
                self.throw("FAIL: reinit THREDDS - '%s'" % result)
                return

            result = auth_read_thredds(reinit_err_url, tuser, tpass)
            index = result.rfind(reinit_err)
            r2 = result[index:]
            findex = r2.find(reinit_fatal)
            if findex != -1:
                i2 = r2[findex:].find('\n')
                errmsg = r2[findex:findex+i2]
                self.throw("FAIL: reinit THREDDS - '%s'\n%s" % (errmsg,r2))

            self.throw("OK")
            
        except Exception, e:
            self.throw("FAIL: reinit_thredds_request fails (%s)"
                       % tb.format_exc())

    # -----------------------------------------------------------------------
    def thredds_request(self, data):
        try:
            (t, xmlfile) = re.split("\s+", data)
            if t != "T":
                self.throw("FAIL: bad request '%s'" % t)
                return
            
            try:
                dest = "/esg/content/thredds/esgcet/1/" \
                       + os.path.basename(xmlfile)
                shutil.copy(xmlfile, dest)
            except Exception, e:
                self.throw("FAIL: shutil.copy(%s, %s) fails (%s; %s = %d)"
                           % (xmlfile, dest, str(e), "os.getuid",
                              os.getuid()))
                return

            self.throw("OK")
            
        except Exception, e:
            self.throw("FAIL: thredds_request fails (%s)" % str(e))

    # -----------------------------------------------------------------------
    def xref_request(self, data):
        try:
            (x, catlist) = re.split("\s+", data)
            if x != "X":
                self.throw("FAIL: bad request '%s'" % x)
                return

            SCIGEST_HOME = os.getenv("SCIGEST_HOME",
                                     "/ccs/proj/techint/esg/scigest")
            os.environ['CLASSPATH'] = "%s/build" % SCIGEST_HOME \
                                      + ":%s/resources" % SCIGEST_HOME
            log("CLASSPATH = '%s'" % os.getenv('CLASSPATH'))
            cmd = ["/usr/local/java/bin/java",
                   "-Djava.ext.dirs=%s/lib/fetched/runtime" % SCIGEST_HOME,
                   "scigest.core.CatalogXref",
                   catlist,
                   "file:///esg/content/thredds/esgcet/catalog.xml"]
            log("running '%s'" % " ".join(cmd))
            proc = subprocess.Popen(cmd,
                                    stdout=subprocess.PIPE,
                                    stderr=subprocess.STDOUT)
            result = "".join(proc.stdout.readlines())
            for line in result.split("\n"):
                log(line)
            log("back from calling CatalogXref")

            if "Exception" in result:
                self.throw("FAIL: Java threw exception")
                return

            self.throw("OK")
            
        except Exception, e:
            self.throw("FAIL: thredds_request fails (%s)" % str(e))

    # -----------------------------------------------------------------------
    def throw(self, msg):
        log("'%s' -> %s" % (msg, self.client_address[0]))
        self.wfile.write(msg + "\n")
        
# ---------------------------------------------------------------------------
class pubd(Daemon):
    # -----------------------------------------------------------------------
    def run(self):
        try:
            p = pwd.getpwnam('tomcat')
            if 0 == os.getuid():
                # os.seteuid(p.pw_uid)
                pass
            # HOST = "scotty.ccs.ornl.gov"
            HOST = socket.gethostname()
            PORT = 40001
            server = ezpub_server((HOST, PORT), ezpub_handler)
            log("-" * 60)
            log("pubd is listening as %s at %s:%s"
                % (pwd.getpwuid(os.getuid())[0], HOST, PORT))
            os.makedirs("/esg/data/testdir")
            os.rmdir("/esg/data/testdir")
            server.serve_forever()
        except Exception, e:
            log("pubd.run failure: '%s'" % str(e))

# ---------------------------------------------------------------------------
def auth_read_thredds(url, username, password):
    tauth_realm = "THREDDS Data Server"
    auth_handler = urllib2.HTTPBasicAuthHandler()
    auth_handler.add_password(realm=tauth_realm,
                              uri=url,
                              user=username,
                              passwd=password)
    opener = urllib2.build_opener(auth_handler)

    urllib2.install_opener(opener)
    try:
        handle = urllib2.urlopen(url)
        page = handle.read()
        handle.close()
    except Exception, e:
        if "maximum recursion depth" in str(e):
            raise StandardError("bad password for %s" % url)
        else:
            log(tb.format_exc())
            return
    return page

# ---------------------------------------------------------------------------
def log(msg):
    now = time.strftime("%Y.%m%d %H:%M:%S")
    sys.stdout.write("%s: %s\n" % (now, msg))
    sys.stdout.flush()
    
# ---------------------------------------------------------------------------
if __name__ == "__main__":
    daemon = pubd('/tmp/esg/pubd/pubd.pid', stdout="/tmp/esg/pubd/pubd.log")
    if len(sys.argv) == 2:
        if 'start' == sys.argv[1]:
            log("pubd starting up")
            daemon.start()
        elif 'stop' == sys.argv[1]:
            log("pubd shutting down")
            daemon.stop()
        elif 'restart' == sys.argv[1]:
            daemon.restart()
        else:
            print "Unknown command"
            sys.exit(2)
        sys.exit(0)
    else:
        print "usage: %s start|stop|restart" % sys.argv[0]
        sys.exit(2)
